import subprocess
import os
from bdtime import Time
import threading
import signal


class RunCmd:
    def __init__(self, log_file_path='tempdir/run_cmd_log/run.log', encoding='utf-8'):
        os.makedirs(os.path.dirname(log_file_path), exist_ok=True)

        self.log_file_path = log_file_path

        self.encoding = encoding

        self.tt = Time()
        self.process = None
        self.output, self.error = None, None

    def get_log_info(self):
        log_file_path = self.log_file_path
        with open(log_file_path, 'r+', encoding=self.encoding) as f:
            ret = f.read()
        return ret

    def save_log_info(self, log_info, override=False):
        log_file_path = self.log_file_path

        if isinstance(log_info, bytes):
            log_info = log_info.decode(self.encoding)

        assert isinstance(log_info, str), 'log_info必须为str类型!'

        if override:
            model = 'w+'
        else:
            model = 'a+'

        if log_info and not log_info.endswith('\n'):
            log_info += '\n'

        with open(log_file_path, model, encoding=self.encoding) as f:
            f.write(f'{log_info}')

    def run_cmd(self, cmd, timeout=5 * 60):
        ENCODING = self.encoding

        # p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
        #                      stderr=subprocess.PIPE)
        # _output, _error = p.communicate(timeout)
        # output = _output.decode(ENCODING)
        # error = _error.decode(ENCODING)
        # return output, error

        def target():
            self.process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            print("--- self.process.pid: ", self.process.pid)
            _output, _error = self.process.communicate()
            output = None if _output is None else _output.decode(ENCODING)
            error = None if _error is None else _error.decode(ENCODING)
            # print("output, error --- ", output, error)
            self.output, self.error = output, error

        thread = threading.Thread(target=target)
        thread.start()
        thread.join(timeout)
        if thread.is_alive():
            # import psutil
            # psutil.
            print(" ~~~ self.process.pid: ", self.process.pid)
            print(f'*** timeout[{timeout}], kill cmd[{cmd}]!')
            # self.process.terminate()
            # self.process.kill()
            # self.process.wait()
            import warnings
            try:
                a = os.kill(self.process.pid, signal.SIGKILL)
                print("已经杀死pid为%s的进程，返回值是:%s" % (self.process.pid, a))
                # os.killpg(self.process.pid, signal.SIGTERM)
            except OSError as e:
                warnings.warn(e)
            # os.killpg(self.process.pid, signal.SIGTERM)
            # thread.join()

        self.process = None
        return self.output, self.error

    def run_commands(self, commands: str, timeout=5 * 60):
        save_log_info = self.save_log_info
        ENCODING = self.encoding

        if commands and commands.strip():
            tt = self.tt

            # 清理旧的日志
            save_log_info(
                f'=== {tt.get_current_beijing_time_str(decimal_places=0)} ===\n\n--- output:\n',
                override=True)

            _commands = commands.strip()
            if _commands.startswith('#!/usr/bin/env bash'):
                _commands = _commands.replace('\r\n', '\n')
                _commands = _commands.replace('\r', '')

                os.makedirs('tempdir/shells', exist_ok=True)
                commands_file_path = 'tempdir/shells/commands.sh'
                with open(commands_file_path, 'w+', encoding=ENCODING) as f:
                    f.write(_commands)
                command_i = f'bash {commands_file_path}'
                p = subprocess.Popen(command_i, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                output, error = p.communicate(timeout)
                _output = output.decode(ENCODING)
                if error:
                    msg = f"\n>>> {command_i}\n*** error:\n {error.decode(ENCODING)}\n"
                    if _output:
                        msg += f"*** output: {_output}\n"
                    save_log_info(msg)
                else:
                    msg = f'>>> {command_i}\n{_output}'
                    save_log_info(msg)
            else:
                command_ls = commands.split('\n')

                for command_i in command_ls:
                    # command_i: str
                    command_i = command_i.strip()
                    if not command_i:
                        continue

                    p = subprocess.Popen(command_i, shell=True, stdout=subprocess.PIPE,
                                         stderr=subprocess.PIPE)
                    output, error = p.communicate()
                    _output = output.decode(ENCODING)
                    if error:
                        msg = f"\n>>> {command_i}\n*** error:\n {error.decode(ENCODING)}\n"
                        if _output:
                            msg += f"*** output: {_output}\n"
                        save_log_info(msg)
                    else:
                        msg = f'>>> {command_i}\n{_output}'
                        save_log_info(msg)
        log_info = self.get_log_info()
        return log_info


run_cmd = RunCmd()


if __name__ == '__main__':
    commands = 'ps -ef | grep wssh | grep -v "grep"'
    output, error = run_cmd.run_cmd(commands)
    print(output)
    if output:
        print('已经在运行中啦~')
